package com.atguigu.srb.core.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.atguigu.srb.core.enums.LendStatusEnum;
import com.atguigu.srb.core.enums.ReturnMethodEnum;
import com.atguigu.srb.core.enums.TransTypeEnum;
import com.atguigu.srb.core.hfb.HfbConst;
import com.atguigu.srb.core.hfb.RequestHelper;
import com.atguigu.srb.core.mapper.*;
import com.atguigu.srb.core.pojo.BO.TransFlowBO;
import com.atguigu.srb.core.pojo.entity.*;
import com.atguigu.srb.core.pojo.vo.BorrowInfoApprovalVO;
import com.atguigu.srb.core.pojo.vo.BorrowerDetailVO;
import com.atguigu.srb.core.service.*;

import com.atguigu.srb.core.util.*;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 标的准备表 服务实现类
 * </p>
 *
 * @author Dragon
 * @since 2021-07-29
 */
@Slf4j
@Service
public class LendServiceImpl extends ServiceImpl<LendMapper, Lend> implements LendService {

    @Resource
    UserInfoMapper userInfoMapper;

    @Resource
    private BorrowerMapper borrowerMapper;

    @Resource
    LendReturnService lendReturnService;
    @Resource
    private BorrowerService borrowerService;
    @Resource
    private DictService dictService;
    @Resource
    LendItemReturnService lendItemReturnService;

    @Resource
    LendItemMapper lendItemMapper;
    @Resource
    TransFlowService transFlowService;
    @Resource
    UserAccountMapper userAccountMapper;

    @Override
    public void createLend(BorrowInfoApprovalVO borrowInfoApprovalVO, BorrowInfo borrowInfo) {
        Lend lend = new Lend();
        lend.setUserId(borrowInfo.getUserId());
        lend.setBorrowInfoId(borrowInfo.getId());
        lend.setLendNo(LendNoUtils.getLendNo());//生成编号
        lend.setTitle(borrowInfoApprovalVO.getTitle());
        lend.setAmount(borrowInfo.getAmount());
        lend.setPeriod(borrowInfo.getPeriod());
        lend.setLendYearRate(borrowInfoApprovalVO.getLendYearRate().divide(new BigDecimal(100)));//从审批对象中获取
        lend.setServiceRate(borrowInfoApprovalVO.getServiceRate().divide(new BigDecimal(100)));//从审批对象中获取
        lend.setReturnMethod(borrowInfo.getReturnMethod());
        lend.setLowestAmount(new BigDecimal(100));
        lend.setInvestAmount(new BigDecimal(0));
        lend.setInvestNum(0);
        lend.setPublishDate(LocalDateTime.now());

        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        LocalDate lendEndDate = LocalDate.parse(borrowInfoApprovalVO.getLendStartDate(), dtf);
        lend.setLendEndDate(lendEndDate);

        lend.setLendInfo(borrowInfoApprovalVO.getLendInfo());

        BigDecimal monthRate = lend.getServiceRate().divide(new BigDecimal(12), 8, BigDecimal.ROUND_DOWN);
        BigDecimal expectAmount = lend.getAmount().multiply(monthRate).multiply(new BigDecimal(lend.getPeriod()));
        lend.setExpectAmount(expectAmount);

        lend.setRealAmount(new BigDecimal(0));
        lend.setStatus(LendStatusEnum.INVEST_RUN.getStatus());
        lend.setCheckTime(LocalDateTime.now());

        lend.setCheckAdminId(1L);
        baseMapper.insert(lend);
    }

    @Override
    public List<Lend> selectList() {
        List<Lend> lendList = baseMapper.selectList(null);
        lendList.forEach(lend -> {
            String returnMethod = dictService.getNameByParentDictCodeAndValue("returnMethod", lend.getReturnMethod());
            String status = LendStatusEnum.getMsgByStatus(lend.getStatus());
            lend.getParam().put("returnMethod", returnMethod);
            lend.getParam().put("status", status);

        });

        return lendList;
    }

    @Override
    public Map<String, Object> getLendDetail(Long id) {
        Lend lend = baseMapper.selectById(id);
        String returnMethod = dictService.getNameByParentDictCodeAndValue("returnMethod", lend.getReturnMethod());
        String status = LendStatusEnum.getMsgByStatus(lend.getStatus());
        lend.getParam().put("returnMethod", returnMethod);
        lend.getParam().put("status", status);
        //根据user_id获取Borrower对象信息
        QueryWrapper<Borrower> Wrapper = new QueryWrapper<>();
        Wrapper.eq("user_id", lend.getUserId());
        Borrower borrower = borrowerMapper.selectOne(Wrapper);
        //组装借款人对象
        BorrowerDetailVO borrowerDetailVOById = borrowerService.getBorrowerDetailVOById(borrower.getId());

        Map<String, Object> HashMap = new HashMap<>();
        HashMap.put("lend", lend);
        HashMap.put("borrower", borrowerDetailVOById);

        return HashMap;
    }

    @Override
    public BigDecimal getInterestCount(BigDecimal invest, BigDecimal yearRate, Integer totalmonth, Integer returnMethod) {

        BigDecimal interestCount = null;
        if (returnMethod.intValue() == ReturnMethodEnum.ONE.getMethod()) {
            interestCount = Amount1Helper.getInterestCount(invest, yearRate, totalmonth);
        } else if (returnMethod.intValue() == ReturnMethodEnum.TWO.getMethod()) {
            interestCount = Amount2Helper.getInterestCount(invest, yearRate, totalmonth);
        } else if (returnMethod.intValue() == ReturnMethodEnum.THREE.getMethod()) {
            interestCount = Amount3Helper.getInterestCount(invest, yearRate, totalmonth);
        } else if (returnMethod.intValue() == ReturnMethodEnum.FOUR.getMethod()) {
            interestCount = Amount4Helper.getInterestCount(invest, yearRate, totalmonth);
        }
        return interestCount;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void makeLoan(Long id) {
        //先调用汇付宝 放款
        Lend lend = baseMapper.selectById(id);
        //调用汇付宝之后，根据返回结果(修改lend标的，修改借款人和投资人账户信息)
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("agentId", HfbConst.AGENT_ID);
        paramMap.put("agentProjectCode", lend.getLendNo());//标的编号
        String agentBillNo = LendNoUtils.getLoanNo();//放款编号
        paramMap.put("agentBillNo", agentBillNo);

        //平台服务费率
        //月年化
        BigDecimal serviceMonthRate = lend.getServiceRate().divide(new BigDecimal(12), 8, BigDecimal.ROUND_DOWN);
        //平台预期收益 = 已投金额 * 月年化 * 标的期数
        BigDecimal serviceExpectAmount = lend.getInvestAmount().multiply(serviceMonthRate).multiply(new BigDecimal(lend.getPeriod()));

        paramMap.put("mchFee", serviceExpectAmount);
        paramMap.put("timestamp", RequestHelper.getTimestamp());
        String sign = RequestHelper.getSign(paramMap);
        paramMap.put("sign", sign);

        log.info("放款参数：" + JSONObject.toJSONString(paramMap));

        JSONObject jsonObject = RequestHelper.sendRequest(paramMap, HfbConst.MAKE_LOAD_URL);

        //调用汇付宝之后,根据返回结果（修改lend标的，修改借款人和投资人账户信息),生成交易流水

        //修改lend标的
        lend.setRealAmount(new BigDecimal("0"));
        lend.setExpectAmount(serviceExpectAmount);
        lend.setStatus(LendStatusEnum.PAY_RUN.getStatus());
        lend.setPaymentTime(LocalDateTime.now());
        baseMapper.updateById(lend);


        Long userId = lend.getUserId();
        UserInfo userInfo = userInfoMapper.selectById(userId);
        String bindCode = userInfo.getBindCode();
        BigDecimal voteAmt = new BigDecimal(jsonObject.getString("voteAmt"));
        userAccountMapper.updateAccount(bindCode, voteAmt, new BigDecimal(0));
        //新增借款人交易流水
        TransFlowBO transFlowBO = new TransFlowBO(
                agentBillNo,
                bindCode,
                voteAmt,
                TransTypeEnum.BORROW_BACK,
                "借款放款到账，编号：" + lend.getLendNo()
        );
        transFlowService.saveTransFlow(transFlowBO);
        QueryWrapper<LendItem> QueryWrapper = new QueryWrapper<>();
        QueryWrapper.eq("lend_id", lend.getId());
        List<LendItem> lendItems = lendItemMapper.selectList(QueryWrapper);

        for (LendItem lendItem : lendItems) {
            //修改投资人用户信息
            Long investUserId = lendItem.getInvestUserId();
            String investBindCode = userInfoMapper.selectById(investUserId).getBindCode();
            BigDecimal investAmount = lendItem.getInvestAmount();
            userAccountMapper.updateAccount(investBindCode, new BigDecimal("0"), investAmount.negate());
            //生成投资人流水


            TransFlowBO investTransFlowBO = new TransFlowBO(
                    lendItem.getLendItemNo(),
                    investBindCode,
                    investAmount,
                    TransTypeEnum.INVEST_UNLOCK,
                    "冻结资金转出，出借放款，编号:" + lend.getLendNo()
            );
            transFlowService.saveTransFlow(investTransFlowBO);
        }


        //TODO

        repaymentPlan(lend);


    }

    private void repaymentPlan(Lend lend) {

        QueryWrapper<LendItem> QueryWrapper = new QueryWrapper<>();
        QueryWrapper.eq("lend_id", lend.getId());
        List<LendItem> lendItems = lendItemMapper.selectList(QueryWrapper);

        //在尚荣宝放款过程中更新srb账户信息 生成交易流水，生成还款计划，后生成回款计划
        //生成还款计划
        Map<String, Object> lendReturnMap = new HashMap<>();
        Integer period = lend.getPeriod();
        for (int i = 1; i < period+1; i++) {

            LendReturn lendReturn = new LendReturn();

            //每生成一期还款计划  就会生成对应的一期回款计划


            lendReturn.setReturnNo(LendNoUtils.getReturnNo());
            lendReturn.setLendId(lend.getId());
            lendReturn.setBorrowInfoId(lend.getBorrowInfoId());
            lendReturn.setUserId(lend.getUserId());
            lendReturn.setAmount(lend.getAmount());
            lendReturn.setBaseAmount(lend.getInvestAmount());
            lendReturn.setLendYearRate(lend.getLendYearRate());
            lendReturn.setCurrentPeriod(i);//当前期数
            lendReturn.setReturnMethod(lend.getReturnMethod());


            lendReturnService.save(lendReturn);

            BigDecimal periodPrincipal = new BigDecimal("0");
            BigDecimal periodInterest = new BigDecimal("0");
            for (LendItem lendItem : lendItems) {
                //每一期的还款本金，还款利息，还款总额
                //对应产生每一期的回款计划
                Map<String, BigDecimal> lendItemReturnAmountMap = returnInvest(lendItem, i, lendReturn.getId(), lend);
                BigDecimal itemPrincipal = lendItemReturnAmountMap.get("principal");
                BigDecimal itemInterest = lendItemReturnAmountMap.get("interest ");

               periodPrincipal = periodPrincipal.add(itemPrincipal);
               periodInterest=periodInterest.add(itemInterest);


            }
            lendReturn.setPrincipal(periodPrincipal);
            lendReturn.setInterest(periodInterest);
            lendReturn.setTotal(periodPrincipal.add(periodInterest));
            lendReturnService.updateById(lendReturn);

        }


    }

    private Map<String, BigDecimal> returnInvest(LendItem lendItem, Integer period, Long LendReturnId, Lend lend) {

        Map<Integer, BigDecimal> perMonthPrincipal = new HashMap<>();
        Map<Integer, BigDecimal> perMonthInterest = new HashMap<>();

        Map<String, BigDecimal> resultMap = new HashMap<>();
        Integer returnMethod = lend.getReturnMethod();
        //还款方式  四种方式的哪一种
        if (returnMethod == ReturnMethodEnum.ONE.getMethod()) {
            perMonthPrincipal = Amount1Helper.getPerMonthPrincipal(lendItem.getInvestAmount(), lend.getLendYearRate(), lend.getPeriod());
            perMonthInterest = Amount1Helper.getPerMonthInterest(lendItem.getInvestAmount(), lend.getLendYearRate(), lend.getPeriod());
        }
        if (returnMethod == ReturnMethodEnum.TWO.getMethod()) {
            perMonthPrincipal = Amount2Helper.getPerMonthPrincipal(lendItem.getInvestAmount(), lend.getLendYearRate(), lend.getPeriod());
            perMonthInterest = Amount2Helper.getPerMonthInterest(lendItem.getInvestAmount(), lend.getLendYearRate(), lend.getPeriod());
        }

        if (returnMethod == ReturnMethodEnum.THREE.getMethod()) {
            perMonthPrincipal = Amount3Helper.getPerMonthPrincipal(lendItem.getInvestAmount(), lend.getLendYearRate(), lend.getPeriod());
            perMonthInterest = Amount3Helper.getPerMonthInterest(lendItem.getInvestAmount(), lend.getLendYearRate(), lend.getPeriod());
        }
        if (returnMethod == ReturnMethodEnum.FOUR.getMethod()) {
            perMonthPrincipal = Amount4Helper.getPerMonthPrincipal(lendItem.getInvestAmount(), lend.getLendYearRate(), lend.getPeriod());
            perMonthInterest = Amount4Helper.getPerMonthInterest(lendItem.getInvestAmount(), lend.getLendYearRate(), lend.getPeriod());
        }
        resultMap.put("principal", perMonthPrincipal.get("period"));
        resultMap.put("interest", perMonthInterest.get("period"));
      //将当前投资人的当期汇款计划存入数据库
        LendItemReturn lendItemReturn = new LendItemReturn();
        lendItemReturn.setLendReturnId(LendReturnId);
        lendItemReturn.setLendItemId(lendItem.getId());
        lendItemReturn.setInvestUserId(lendItem.getInvestUserId());
        lendItemReturn.setLendId(lend.getId());
        lendItemReturn.setInvestAmount(lendItem.getInvestAmount());
        lendItemReturn.setLendYearRate(lend.getLendYearRate());
        lendItemReturn.setCurrentPeriod(period);
        lendItemReturn.setReturnMethod(lend.getReturnMethod());

        lendItemReturn.setPrincipal(perMonthPrincipal.get(period));
        lendItemReturn.setInterest(perMonthInterest.get(period));

        lendItemReturn.setTotal(lendItemReturn.getPrincipal().add(lendItemReturn.getInterest()));
        lendItemReturn.setFee(new BigDecimal("0"));
        lendItemReturn.setReturnDate(lend.getLendStartDate().plusMonths(period));
        //是否逾期，默认未逾期
        lendItemReturn.setOverdue(false);
        lendItemReturn.setStatus(0);
         lendItemReturnService.save(lendItemReturn);
        return resultMap;
    }
}
